package comportamento.neuronio;

import java.util.Random;

import comportamento.funcaoativacao.IFuncaoAtivacao;

import concreto.funcaoativacao.FuncaoAtivacaoDegrau;
import concreto.funcaoativacao.FuncaoAtivacaoGaussiana;
import concreto.funcaoativacao.FuncaoAtivacaoLinear;
import concreto.funcaoativacao.FuncaoAtivacaoSignada;
import concreto.funcaoativacao.FuncaoAtivacaoSinal;

public abstract class INeuronioAbstrato {

    protected IFuncaoAtivacao funcaoAtivacao = new FuncaoAtivacaoLinear();
    protected double[] wk = null;
    protected double uk = 0;
    protected double[] estimulos;
    protected double y = 0;
    protected double limiar = 0.0;
    protected double bk = 0.0;

    private Random random = new Random();

    public static int ATIVACAO_LINEAR = 0;
    public static int ATIVACAO_DEGRAU = 1;
    public static int ATIVACAO_GAUSSIANA = 2;
    public static int ATIVACAO_SIGNADA = 3;
    public static int ATIVACAO_SINAL = 4;

    /**
     * Efetua a ponderação do vetor de estimulos.
     * 
     * @return
     */
    public abstract double[] ponderarEstimulos(double[] estimulos);

    /**
     * Devolve uma resposta dado um estimulo.
     * 
     * @param estimulos
     * @return resposta
     */
    public abstract double resposta(double[] estimulos);

    /**
     * Calcula o valor de Uk.
     * 
     * @param vetorPesosConexao
     * @return valor de Uk
     */
    public abstract void calcularUk(double[] vetorPesosConexao); 

    /**
     * Gera os pesos aleatoriamente para o número de entradas solicitada.
     * 
     * @param quantidadeEntradas
     * @return vetor de pesos
     */
    public abstract void geraPesosConexoes(int quantidadeEntradas);

    /**
     * Seleciona a função de ativação requisitada para o neuronio.
     * 
     * @param funcao
     */
    public void selecionarFuncaoAtivacao(int funcao) throws IllegalArgumentException {

	if(funcao < 0 || funcao > 4)
	    throw new IllegalArgumentException("Informe um código válido de função de ativação!");

	switch (funcao) {
	case 0: funcaoAtivacao = new FuncaoAtivacaoLinear(); break;
	case 1: funcaoAtivacao = new FuncaoAtivacaoDegrau(); break;
	case 2: funcaoAtivacao = new FuncaoAtivacaoGaussiana(); break;
	case 3: funcaoAtivacao = new FuncaoAtivacaoSignada(); break;
	case 4: funcaoAtivacao = new FuncaoAtivacaoSinal(); break;
	}
    }

    public double gerarValorRandomico() {

	double n = random.nextDouble();
	return (random.nextBoolean() ? n : n * -1);
    }

    public double erroQuadratico(double[] vetor){

	double soma = 0;

	for(int i=0; i < vetor.length; i++){
	    soma += Math.pow(vetor[i], 2);
	}
	
	return soma;
    }

    /**
     * Retorna o valor do limiar.
     * 
     * @return valor do limiar
     */
    public double valorLimiar() {

	return this.limiar;
    }
}
